package com.github.libretube.util

import android.util.Log
import com.github.libretube.api.MediaServiceRepository
import com.github.libretube.api.obj.ContentItem
import com.github.libretube.api.obj.DeArrowContent
import com.github.libretube.api.obj.StreamItem
import com.github.libretube.api.obj.StreamItem.Companion.TYPE_STREAM
import com.github.libretube.api.obj.Streams
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.extensions.toID
import com.github.libretube.helpers.PreferenceHelper
import java.util.TreeSet

object DeArrowUtil {
    private fun extractTitleAndThumbnail(content: DeArrowContent): Pair<String?, String?> {
        val title = content.titles.firstOrNull { it.votes >= 0 || it.locked }?.title
        val thumbnail = content.thumbnails.firstOrNull {
            it.thumbnail != null && !it.original && (it.votes >= 0 || it.locked)
        }?.thumbnail

        return title to thumbnail
    }


    private suspend fun fetchDeArrowContent(videoIds: List<String>): Map<String, DeArrowContent>? {
        val videoIdsString = videoIds.mapTo(TreeSet()) { it }.joinToString(",")

        return try {
            MediaServiceRepository.instance.getDeArrowContent(videoIdsString)
        } catch (e: Exception) {
            Log.e(this::class.java.name, "Failed to fetch DeArrow content: ${e.message}")
            null
        }
    }

    /**
     * Apply the new titles and thumbnails generated by DeArrow to the streams item
     */
    suspend fun deArrowStreams(streams: Streams, vidId: String): Streams {
        if (!PreferenceHelper.getBoolean(PreferenceKeys.DEARROW, false)) return streams

        val videoIds = listOf(vidId) + streams.relatedStreams.mapNotNull { it.url?.toID() }
        val response = fetchDeArrowContent(videoIds) ?: return streams

        response[vidId]?.let { data ->
            val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
            if (newTitle != null) streams.title = newTitle
            if (newThumbnail != null) streams.thumbnailUrl = newThumbnail
        }

        streams.relatedStreams.forEach { streamItem ->
            val videoId = streamItem.url?.toID() ?: return@forEach
            response[videoId]?.let { data ->
                val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
                if (newTitle != null) streamItem.title = newTitle
                if (newThumbnail != null) streamItem.thumbnail = newThumbnail
            }
        }

        return streams
    }

    /**
     * Apply the new titles and thumbnails generated by DeArrow to the stream items
     */
    suspend fun deArrowStreamItems(streamItems: List<StreamItem>): List<StreamItem> {
        if (!PreferenceHelper.getBoolean(PreferenceKeys.DEARROW, false)) return streamItems
        if (streamItems.isEmpty()) return streamItems

        val videoIds = streamItems.mapNotNull { it.url?.toID() }
        val response = fetchDeArrowContent(videoIds) ?: return streamItems

        streamItems.forEach { streamItem ->
            val videoId = streamItem.url?.toID() ?: return@forEach
            response[videoId]?.let { data ->
                val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
                if (newTitle != null) streamItem.title = newTitle
                if (newThumbnail != null) streamItem.thumbnail = newThumbnail
            }
        }

        return streamItems
    }

    /**
     * Apply the new titles and thumbnails generated by DeArrow to the content items
     */
    suspend fun deArrowContentItems(contentItems: List<ContentItem>): List<ContentItem> {
        if (!PreferenceHelper.getBoolean(PreferenceKeys.DEARROW, false)) return contentItems

        val videoIds = contentItems
            .filter { it.type == TYPE_STREAM }
            .map { it.url.toID() }

        if (videoIds.isEmpty()) return contentItems

        val response = fetchDeArrowContent(videoIds) ?: return contentItems

        contentItems.forEach { contentItem ->
            val videoId = contentItem.url.toID()
            response[videoId]?.let { data ->
                val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
                if (newTitle != null) contentItem.title = newTitle
                if (newThumbnail != null) contentItem.thumbnail = newThumbnail
            }
        }

        return contentItems
    }
}

@JvmName("deArrowStreamItems")
suspend fun List<StreamItem>.deArrow() = DeArrowUtil.deArrowStreamItems(this)

@JvmName("deArrowContentItems")
suspend fun List<ContentItem>.deArrow() = DeArrowUtil.deArrowContentItems(this)

@JvmName("deArrowStreams")
suspend fun Streams.deArrow(videoId: String) = DeArrowUtil.deArrowStreams(this, videoId)